home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Utilities Experience
/
The Utilities Experience - Volume 1.iso
/
software
/
emulation
/
frodo
/
src
/
6510.asm
< prev
next >
Wrap
Assembly Source File
|
1996-01-29
|
61KB
|
3,396 lines
*
* 6510.asm - 6510-Emulation (eigener Task)
*
* Copyright (C) 1994-1996 by Christian Bauer
*
*
* Anmerkungen:
* ------------
*
* Register d0/d1/a4 - WICHTIG:
* - Der Emulator geht davon aus, daß die MSWs von d0 und d1 immer Null
* sind. Denn dadurch kann das C64-RAM mittels (RAMPTR,d0.l) ohne
* Vorzeichen indiziert angesprochen werden.
* - Die Makros Read#?Zero#? und Read#?Ind#? gehen zusätlich davon aus,
* daß nur das untere Byte von d0 Null ist, da diese Makros immer nur
* am Anfang eines Befehls stehen und d0 vom Next-Makro noch gelöscht
* ist
* - Register a4 wird zur Near-Adressierung verwendet
*
* Speicherkonfigurationen:
*
* $01 $a000-$bfff $d000-$dfff $e000-$ffff
* -----------------------------------------------
* 0 RAM RAM RAM
* 1 RAM Char-ROM RAM
* 2 RAM Char-ROM Kernal-ROM
* 3 Basic-ROM Char-ROM Kernal-ROM
* 4 RAM RAM RAM
* 5 RAM I/O RAM
* 6 RAM I/O Kernal-ROM
* 7 Basic-ROM I/O Kernal-ROM
*
* Zugriff auf den C64-Speicher:
* - Fast alle Speicherzugriffe laufen über die ReadByte/WriteByte-Makros,
* die die eingestellte Speicherkonfiguration dadurch berücksichtigen,
* daß die oberen 8 Adreßbits als Index in eine Sprungtabelle
* (ReadWriteTab) dienen, die Zeiger auf die ReadByte*/WriteByte*-
* Routinen enthalten, über die der tatsächliche Zugriff erfolgt.
* Für jede der 8 Speicherkonfigurationen existiert jeweils eine solche
* Tabelle Bei einer Änderung der Speicherkonfiguration (NewConfig)
* wird der Zeiger auf die Tabelle (RWTAB) geändert.
* - Das LESEN aus der Zero-Page geschieht immer direkt,
* da dort keine Register liegen ($00/$01 werden auch im RAM abgelegt)
* - Beim Schreiben in die Zero-Page wird nur auf $00/$01 getestet,
* ansonsten direkt zugegriffen
* - Der Stack wird immer direkt angesprochen
* - Die ReadByte-/WriteByte-Routinen dürfen nur d0-d1/a0-a1 verändern
*
* Programmzähler:
* - Aus Geschwindigkeitsgründen wird der PC durch einen 32-Bit-
* Amiga-Zeiger repräsentiert und über diesen direkt auf den
* Speicher zugegriffen (und nicht über ReadByte). Bei einem
* Sprungbefehl wird aus dem 16-Bit Sprungziel und der aktuellen
* Speicherkonfiguration die neue 32-Bit-Adresse berechnet,
* indem ähnlich zur ReadWriteTab die oberen 8 Bit des Sprungziels
* als Index in die JumpTab verwendet werden. Die darüber aufgerufenen
* Routinen führen die Umrechnung durch.
* - Durch die Art, wie das Hauptprogramm den Speicher anfordert,
* entsprechen die unteren 16 Bit des 32-Bit-PCs immer der
* 16-Bit-C64-Adresse. Das erleichtert erheblich das Ablegen des
* PC auf dem Stack, da dazu einfach nur die unteren 16 Bit
* genommen werden müssen (ansonsten müßte man je nach RAM/ROM-
* Bereich erst die jeweilige Basisadresse subtrahieren).
* - Im RAM-Bereich $10000-$100ff wird der Opcode $d2 installiert,
* der den PC auf $0000-$00ff umrechnet, falls ein Programm den
* Wraparound macht
* - Durch diese Art der PC-Verwaltung bestehen folgende Inkompatibilitäten:
* - Ein Branch oder ein Hineinlaufen in einen anderen Speicherbereich
* (z.B. RAM->ROM) funktioniert nicht. Das sollte allerdings kein
* Problem darstellen.
* - Ein Sprung in den I/O-Bereich ist z.Z. nicht möglich
*
* Condition-Codes:
* - Die Emulation verwendet zwei Register, um die Prozessorflags zu
* speichern: RCCR und RP.
* - RCCR ist ein Abbild des 680x0-CCR und wird nach den entsprechenden
* Operationen mit "move ccr,RCCR" gelesen. Von RCCR werden nur das N-
* und das Z-Flag verwendet.
* - Die einzigen Opcodes, die V ändern, sind ADC, SBC, CLV, PLP und RTI.
* Darum wird das V-Flag nicht aus dem 680x0-V-Flag erzeugt, sondern
* gegebenenfalls von Hand gesetzt.
* - Im oberen Byte (Bit 8-15) von RP sind die 6510-Flags V,B,D und I
* in der selben Anordnung wie beim 6510 gespeichert. Das untere Byte
* enthält in Bit 0 das Carry-Flag in 6510-Interpretation (bei SBC und
* CMP/CPX/CPY inverse Bedeutung zum 680x0), das bei den entsprechenden
* Opcodes aus dem CCR gelesen (und ggf. invertiert) wird. Der Einfachheit
* halber wird immer das ganze untere Byte von CCR gelesen, da nur Bit 0
* interessant ist.
*
* Opcode-Ausführung:
* - Es gibt keine Fetch-Decode-Schleife, sondern jede Opcode-Routine
* enthält am Schluß den Code, der den nächsten Befehl ausführt
* ("Next"-Makro).
* - Die Verzweigung in die einzelnen Opcode-Routinen geschieht über
* eine Sprungtabelle, die OpcodeTable.
*
* Zyklenzähler/Periodic/Interrupts:
* - Die Variable CyclesLeft enthält die Anzahl Zyklen, die dem 6510 in
* der augenblicklichen Rasterzeile noch zur Verfügung stehen.
* - Ein Zeiger auf CyclesLeft steht in (CYCPTR) (wg. schnellerer
* Adressierung).
* - Nach jeder Opcode-Ausführung wird dieser Zähler um die Zyklenzahl
* des gerade ausgeführten Befehls erniedrigt. Dazu wird dem Next-Makro
* die Anzahl Zyklen übergeben. Unterschreitet der Zähler Null, wird
* die Routine "Periodic" aufgerufen.
* - In dieser Routine werden die Unterroutinen von VIC und CIA
* ausgeführt, die die Aktionen für eine Rasterzeile durchführen
* (VIC (Periodic6569): Eine Bildschirmzeile aufbauen, CIA
* (Periodic6526): Timer zählen)
* - In Periodic6569 wird der Zyklenzähler neu gesetzt (der Wert hängt
* davon ab, ob eine Bad Line stattfand oder nicht)
*
* Interrupts:
* - Die Haupt-Interruptquellen sind VIC und CIA, daher prüft der
* Emulator das Auftreten eines Interrupts im Rahmen der Periodic-
* Routine
* - Es gibt folgende Interrupt-Möglichkeiten (Prioritäten):
* - RESET, Sprung nach ($FFFC) oder 6510-Task beenden (RESETIsEXIT-Flag)
* - NMI, Sprung nach ($FFFA)
* - VIC-IRQ, I-Flag wird geprüft, Sprung nach ($FFFE)
* - CIA-IRQ, I-Flag wird geprüft, Sprung nach ($FFFE)
* - Die Aufteilung in VIC- und CIA-IRQ erleichtert die Handhabung, wenn
* beide IRQs gleichzeitig auftreten
* - Die einzige Möglichkeit, außerhalb des Periodic einen Interrupt
* auszulösen, ist das Löschen des I-Flags, wenn ein IRQ ansteht.
* Die Opcode-Routinen für PLP, RTI und CLI enthalten deswegen besondere
* Abfragen, die ggf. in den Interrupt-Handler verzweigen.
*
* Erweiterungen:
* - Über den Opcode $f2 sind die IEC-Routinen implementiert. Dem Opcode
* folgt ein Byte, das die Nummer der auzurufenden Routine angibt.
*
* Inkompatibilitäten:
* - ($ff),Y-Adressierung liest das zweite Byte der indirekten Adresse
* aus $0100 statt $0000. Dies geschieht aus Geschwindigkeitsgründen,
* der korrekte Code ist im Makro ReadAdrIndY auskommentiert.
* - In der Verwaltung des PCs bestehen einige Ungenauigkeiten (siehe
* Abschnitt "Programmzähler")
* - RMW-Befehle sollten erst die Originaldaten und dann die geänderten
* schreiben, aber das spielt nur eine Rolle für Register wie das
* VIC-IRQFLAG-Register, das in 6569.asm deswegen speziell behandelt wird
* - Zyklen werden nur für ganze Befehle gezählt, Extra-Zyklen für
* Seitenüberschreitungen werden nicht berechnet (dies betrifft die
* Adressierungsarten xxxx,X xxxx,Y (xx),Y und die Branch-Befehle)
* - Der Kassettenschalter ist immer geschlossen
* - RRA und ISB kennen keinen Dezimalmodus
*
MACHINE 68020
INCLUDE "exec/types.i"
INCLUDE "exec/macros.i"
INCLUDE "exec/execbase.i"
INCLUDE "exec/nodes.i"
INCLUDE "dos/dos.i"
INCLUDE "dos/dostags.i"
INCLUDE "Frodo_rev.i"
CATCOMP_NUMBERS = 1
INCLUDE "LocStrings.i"
XREF _SysBase
XREF _DOSBase
XREF _IntuitionBase
XREF GetString ;Strings.o
XREF TheLocale
XDEF TheRAM ;Main.asm
XDEF TheBasic
XDEF TheKernal
XDEF TheChar
XDEF TheColor
XREF MainTask
XREF Random
XREF ResetC64
XREF _InitDisplayFrom6510 ;Display.c
XREF _ExitDisplayFrom6510
XREF _EmulToBack
XREF _EmulToFront
XREF ReadFrom6526A ;6526.asm
XREF ReadFrom6526B
XREF WriteTo6526A
XREF WriteTo6526B
XREF ReadFrom6569 ;6569.asm
XREF WriteTo6569
XREF Periodic6569
XREF ReadFrom6581 ;6581.asm
XREF WriteTo6581
XREF IECOut ;IEC.asm
XREF IECOutATN
XREF IECOutSec
XREF IECIn
XREF IECSetATN
XREF IECRelATN
XREF IECTurnaround
XREF IECRelease
XDEF Init6510
XDEF Reset6510
XDEF Start6510
XDEF Stop6510
XDEF _Pause6510
XDEF _Resume6510
XDEF _SAMReadByte
XDEF _SAMWriteByte
XDEF Localize6510
XDEF IntIsRESET
XDEF IntIsNMI
XDEF IntIsVICIRQ
XDEF IntIsCIAIRQ
XDEF NMIState
XDEF CyclesLeft
XDEF CPUTask
XDEF Peri6569Cont
XDEF Peri6526Cont
XDEF IsFrodoSC
XDEF _IsFrodoSC
XDEF _InvokeSAMSet
NEAR a4,-2
XREF _DATA_BAS_
SECTION "text",CODE
FAR
**
** Definitionen
**
; Bitdefinitionen für RP (6510-Statusregister)
InterruptBit = 10 ;Interrupts abgeschaltet
InterruptMask = $0400
DecimalBit = 11 ;Dezimalmodus
DecimalMask = $0800
OverflowBit = 14 ;Arith. Überlauf
OverflowMask = $4000
; Registerbelegung
RA EQUR d2 ;A
RX EQUR d3 ;X
RY EQUR d4 ;Y
RS EQUR d5 ;S (16-Bit, $01xx)
RCCR EQUR d6 ;CCR, nur N und Z
RP EQUR d7 ;Oberes Byte: 6510-Status ohne N,Z und C
;Unteres Byte: Carry in 6510-Interpretation
RWTAB EQUR a2 ;Zeiger auf ReadByte/WriteByte-Sprungtabelle
;256*8*8+RWTAB zeigt auf JumpTab
CYCPTR EQUR a3 ;Zeiger auf CyclesLeft
RAMPTR EQUR a5 ;Zeiger auf C64-RAM
RPC EQUR a6 ;PC (32-Bit Amiga-Adresse, untere 16 Bit
; stimmen mit C64-PC überein)
**
** Emulation vorbereiten (Sprungtabellen aufbauen)
**
; ReadWriteTabs aufbauen
Init6510 lea ReadWriteTab0,a0 ;Alle mit RAM vorbelegen
move.w #256*8-1,d0
1$ move.l #ReadByteRAM,(a0)+
move.l #WriteByteRAM,(a0)+
dbra d0,1$
move.l #WriteBytePage0,ReadWriteTab0+4 ;Zeropage immer speziell
move.l #WriteBytePage0,ReadWriteTab1+4
move.l #WriteBytePage0,ReadWriteTab2+4
move.l #WriteBytePage0,ReadWriteTab3+4
move.l #WriteBytePage0,ReadWriteTab4+4
move.l #WriteBytePage0,ReadWriteTab5+4
move.l #WriteBytePage0,ReadWriteTab6+4
move.l #WriteBytePage0,ReadWriteTab7+4
lea ReadWriteTab3+160*8,a0 ;Basic-ROM
moveq #31,d0
21$ move.l #ReadByteBasic,(a0)+
addq.l #4,a0
dbra d0,21$
lea ReadWriteTab7+160*8,a0
moveq #31,d0
22$ move.l #ReadByteBasic,(a0)+
addq.l #4,a0
dbra d0,22$
lea ReadWriteTab2+224*8,a0 ;Kernal-ROM
moveq #31,d0
31$ move.l #ReadByteKernal,(a0)+
addq.l #4,a0
dbra d0,31$
lea ReadWriteTab3+224*8,a0
moveq #31,d0
32$ move.l #ReadByteKernal,(a0)+
addq.l #4,a0
dbra d0,32$
lea ReadWriteTab6+224*8,a0
moveq #31,d0
33$ move.l #ReadByteKernal,(a0)+
addq.l #4,a0
dbra d0,33$
lea ReadWriteTab7+224*8,a0
moveq #31,d0
34$ move.l #ReadByteKernal,(a0)+
addq.l #4,a0
dbra d0,34$
lea ReadWriteTab5+208*8,a0 ;I/O-Bereich
bsr InitIOPages
lea ReadWriteTab6+208*8,a0
bsr InitIOPages
lea ReadWriteTab7+208*8,a0
bsr InitIOPages
lea ReadWriteTab1+208*8,a0 ;Char-ROM
moveq #15,d0
41$ move.l #ReadByteChar,(a0)+
addq.l #4,a0
dbra d0,41$
lea ReadWriteTab2+208*8,a0
moveq #15,d0
42$ move.l #ReadByteChar,(a0)+
addq.l #4,a0
dbra d0,42$
lea ReadWriteTab3+208*8,a0
moveq #15,d0
43$ move.l #ReadByteChar,(a0)+
addq.l #4,a0
dbra d0,43$
; JumpTabs aufbauen
lea JumpTab0,a0 ;Alle mit RAM vorbelegen
move.w #256*8-1,d0
6$ move.l #JumpToRAM,(a0)+
addq.l #4,a0
dbra d0,6$
lea JumpTab3+160*8,a0 ;Basic-ROM
moveq #31,d0
71$ move.l #JumpToBasic,(a0)+
addq.l #4,a0
dbra d0,71$
lea JumpTab7+160*8,a0
moveq #31,d0
72$ move.l #JumpToBasic,(a0)+
addq.l #4,a0
dbra d0,72$
lea JumpTab2+224*8,a0 ;Kernal-ROM
moveq #31,d0
81$ move.l #JumpToKernal,(a0)+
addq.l #4,a0
dbra d0,81$
lea JumpTab3+224*8,a0
moveq #31,d0
82$ move.l #JumpToKernal,(a0)+
addq.l #4,a0
dbra d0,82$
lea JumpTab6+224*8,a0
moveq #31,d0
83$ move.l #JumpToKernal,(a0)+
addq.l #4,a0
dbra d0,83$
lea JumpTab7+224*8,a0
moveq #31,d0
84$ move.l #JumpToKernal,(a0)+
addq.l #4,a0
dbra d0,84$
lea JumpTab1+208*8,a0 ;Char-ROM
moveq #15,d0
85$ move.l #JumpToChar,(a0)+
addq.l #4,a0
dbra d0,85$
lea JumpTab2+208*8,a0
moveq #15,d0
86$ move.l #JumpToChar,(a0)+
addq.l #4,a0
dbra d0,86$
lea JumpTab3+208*8,a0
moveq #15,d0
87$ move.l #JumpToChar,(a0)+
addq.l #4,a0
dbra d0,87$
lea JumpTab5+208*8,a0 ;I/O-Bereich
moveq #15,d0
88$ move.l #JumpToIO,(a0)+
addq.l #4,a0
dbra d0,88$
lea JumpTab6+208*8,a0
moveq #15,d0
89$ move.l #JumpToIO,(a0)+
addq.l #4,a0
dbra d0,89$
lea JumpTab7+208*8,a0
moveq #15,d0
810$ move.l #JumpToIO,(a0)+
addq.l #4,a0
dbra d0,810$
rts
InitIOPages move.l #ReadByteVIC,(a0)+
move.l #WriteByteVIC,(a0)+
move.l #ReadByteVIC,(a0)+
move.l #WriteByteVIC,(a0)+
move.l #ReadByteVIC,(a0)+
move.l #WriteByteVIC,(a0)+
move.l #ReadByteVIC,(a0)+
move.l #WriteByteVIC,(a0)+
move.l #ReadByteSID,(a0)+
move.l #WriteByteSID,(a0)+
move.l #ReadByteSID,(a0)+
move.l #WriteByteSID,(a0)+
move.l #ReadByteSID,(a0)+
move.l #WriteByteSID,(a0)+
move.l #ReadByteSID,(a0)+
move.l #WriteByteSID,(a0)+
move.l #ReadByteColor,(a0)+
move.l #WriteByteColor,(a0)+
move.l #ReadByteColor,(a0)+
move.l #WriteByteColor,(a0)+
move.l #ReadByteColor,(a0)+
move.l #WriteByteColor,(a0)+
move.l #ReadByteColor,(a0)+
move.l #WriteByteColor,(a0)+
move.l #ReadByteCIA1,(a0)+
move.l #WriteByteCIA1,(a0)+
move.l #ReadByteCIA2,(a0)+
move.l #WriteByteCIA2,(a0)+
move.l #ReadByteUndef,(a0)+
move.l #WriteByteUndef,(a0)+
move.l #ReadByteUndef,(a0)+
move.l #WriteByteUndef,(a0)
rts
**
** 6510 zurücksetzen
**
Reset6510 st.b IntIsRESET
rts
**
** 6510-Task starten
** Rückgabe: d0#0 = Fehler
**
; Signale einrichten
Start6510 move.l _SysBase,a6
moveq #-1,d0
JSRLIB AllocSignal
move.b d0,ReadySig
moveq #0,d1
bset d0,d1
move.l d1,ReadySet
moveq #-1,d0
JSRLIB AllocSignal
move.b d0,InvokeSAMSig
moveq #0,d1
bset d0,d1
move.l d1,InvokeSAMSet
; Task starten
move.l _DOSBase,a6
move.l #ProcTags,d1
JSRLIB CreateNewProc
move.l d0,CPUProc
beq 1$
; Auf Signal warten
move.l _SysBase,a6
move.l ReadySet,d0
JSRLIB Wait
moveq #0,d0 ;Alles OK
rts
; Fehler aufgetreten
1$ moveq #-1,d0
rts
**
** 6510-Task stoppen
**
; Task stoppen
Stop6510 move.l _SysBase,a6
tst.l CPUProc
beq 1$
st.b RESETIsEXIT ;EXIT-Reset auslösen
st.b IntIsRESET
move.l ReadySet,d0
JSRLIB Wait
; Signale freigeben
1$ move.b InvokeSAMSig,d0
JSRLIB FreeSignal
move.b ReadySig,d0
JMPLIB FreeSignal
**
** 6510-Task anhalten, Zustand sichern
**
_Pause6510 move.l a6,-(sp)
move.l _SysBase,a6
st.b RESETIsPause ;Pause-Reset auslösen
st.b IntIsRESET
move.l ReadySet,d0
JSRLIB Wait
move.l (sp)+,a6
rts
**
** 6510-Task fortsetzen, Zustand übernehmen
**
_Resume6510 move.l a6,-(sp)
move.l _SysBase,a6
move.l CPUTask,a1 ;Continue-Signal schicken
move.l ContinueSet,d0
JSRLIB Signal
move.l (sp)+,a6
rts
**
** Byte lesen (für SAM)
**
_SAMReadByte moveq #0,d0
move.w 6(sp),d0
movem.l d2/a4/RAMPTR,-(sp)
lea _DATA_BAS_,a4
lea 32766(a4),a4
move.l TheRAM,RAMPTR
move.l d0,d1
lsr.w #8,d1
move.b _SAMMemConfig,d2
and.w #7,d2
move.l (ConfigTab,d2.w*4),a0
move.l (a0,d1.w*8),a0
jsr (a0)
movem.l (sp)+,d2/a4/RAMPTR
rts
**
** Byte schreiben (für SAM)
**
_SAMWriteByte moveq #0,d0
move.w 6(sp),d0
move.l 8(sp),d1
cmp.w #$d000,d0
blo 1$
movem.l d2/a4/RAMPTR,-(sp)
lea _DATA_BAS_,a4
lea 32766(a4),a4
move.l TheRAM,RAMPTR
move.l d0,a1
lsr.w #8,d0
move.b _SAMMemConfig,d2
and.w #7,d2
move.l (ConfigTab,d2.w*4),a0
move.l (4,a0,d0.w*8),a0
jsr (a0)
movem.l (sp)+,d2/a4/RAMPTR
rts
1$ move.l TheRAM,a0
move.b d1,(a0,d0.l)
rts
**
** Strings in Datenstrukturen lokalisieren
**
GetStr MACRO ;Label
lea TheLocale,a0
move.l #\1,d0
jsr GetString
ENDM
Localize6510 GetStr MSG_REQTITLE
move.l d0,IllegalOpReq+8
move.l d0,JumpToIOReq+8
GetStr MSG_REQGADS6
move.l d0,IllegalOpReq+16
GetStr MSG_REQGADS4
move.l d0,JumpToIOReq+16
GetStr MSG_ILLEGALOP
move.l d0,IllegalOpReq+12
GetStr MSG_JUMPTOIO
move.l d0,JumpToIOReq+12
rts
**
** 6510-Emulator
**
** Register:
** d0: Scratch (Oberes Wort muß IMMER Null sein!)
** d1: Scratch (Oberes Wort muß IMMER Null sein!)
** a4: Zeiger auf Variablen
**
NEAR
*
* Makros für Speicherzugriffe und Adreßberechnungen
*
; Ein C64-Byte lesen
; -> d0.w: Adresse
; <- d0.b: Byte
ReadByte MACRO ;[Ziel] (wird ein Ziel angegeben, ist das CCR gültig)
cmp.w #$a000,d0 ;Unterhalb von $a000 ist nur Speicher
blo \@1$
move.w d0,d1
lsr.w #8,d1
move.l (RWTAB,d1.l*8),a0
jsr (a0)
IFGE NARG-1
move.b d0,\1
ENDC
bra \@2$
\@1$
IFGE NARG-1
move.b (RAMPTR,d0.l),\1
ELSE
move.b (RAMPTR,d0.l),d0
ENDC
\@2$
ENDM
; Ein C64-Wort lesen (Als Makro schneller)
; -> d0.w: Adresse
; <- d0.w: Wort (Bytefolge korrigiert)
ReadWord MACRO
move.l d2,RegStore
move.l d0,d2 ;Adresse merken
ReadByte d1
move.l d2,d0 ;Adresse zurückholen
addq.w #1,d0 ;Nächstes Byte
move.b d1,d2 ;Lo-Byte merken
ReadByte
lsl.w #8,d0 ;Hi-Byte richtig schieben
move.b d2,d0 ;Lo-Byte dazunehmen
move.l RegStore,d2
ENDM
; Ein C64-Byte schreiben
; -> d0.w: Adresse (16 bit)
; -> d1.b: Byte
; Adresse steht dann in a1
WriteByte MACRO
cmp.w #$d000,d0 ;Unterhalb von $d000 ist nur Speicher
blo \@1$
move.l d0,a1
lsr.w #8,d0
move.l (4,RWTAB,d0.l*8),a0
jsr (a0)
bra \@2$
\@1$ move.b d1,(RAMPTR,d0.l)
cmp.b #2,d0
bhs \@2$
NewConfig
\@2$
ENDM
; Ein C64-Wort am PC lesen und PC erhöhen
ReadPCWord MACRO
move.w (RPC)+,d0
rol.w #8,d0
ENDM
; Relative Adressierung
ReadByteRel MACRO
move.b (RPC)+,d0
ext.w d0
ENDM
; Absolute Adressierung
ReadAdrAbs MACRO
ReadPCWord
ENDM
ReadByteAbs MACRO ;[Ziel] (wird ein Ziel angegeben, ist das CCR gültig)
ReadAdrAbs
ReadByte \1
ENDM
; Indirekte Adressierung
ReadAdrInd MACRO
ReadPCWord
move.l d2,RegStore
move.l d0,d2 ;Adresse merken
ReadByte d1
move.l d2,d0 ;Adresse zurückholen
addq.b #1,d0 ;Nächstes Byte OHNE Page-Crossing
move.b d1,d2 ;Lo-Byte merken
ReadByte
lsl.w #8,d0 ;Hi-Byte richtig schieben
move.b d2,d0 ;Lo-Byte dazunehmen
move.l RegStore,d2
ENDM
; Zero-Page Adressierung
ReadAdrZero MACRO
move.b (RPC)+,d0
ENDM
ReadByteZero MACRO ;Ziel (CCR ist gültig)
ReadAdrZero
move.b (RAMPTR,d0.l),\1
ENDM
; Absolut,X
ReadAdrAbsX MACRO
ReadPCWord
add.w RX,d0
ENDM
ReadByteAbsX MACRO ;[Ziel] (wird ein Ziel angegeben, ist das CCR gültig)
ReadAdrAbsX
ReadByte \1
ENDM
; Absolut,Y
ReadAdrAbsY MACRO
ReadPCWord
add.w RY,d0
ENDM
ReadByteAbsY MACRO ;[Ziel] (wird ein Ziel angegeben, ist das CCR gültig)
ReadAdrAbsY
ReadByte \1
ENDM
; Zero-Page,X
ReadAdrZeroX MACRO
move.b (RPC)+,d0
add.b RX,d0
ENDM
ReadByteZeroX MACRO ;Ziel (CCR ist gültig)
ReadAdrZeroX
move.b (RAMPTR,d0.l),\1
ENDM
; Zero-Page,Y
ReadAdrZeroY MACRO
move.b (RPC)+,d0
add.b RY,d0
ENDM
ReadByteZeroY MACRO ;Ziel (CCR ist gültig)
ReadAdrZeroY
move.b (RAMPTR,d0.l),\1
ENDM
; (Ind,X)
ReadAdrIndX MACRO
move.b (RPC)+,d0
add.b RX,d0
move.b (RAMPTR,d0.l),d1 ;LSB lesen
addq.b #1,d0
move.b (RAMPTR,d0.l),d0 ;MSB lesen
lsl.w #8,d0
move.b d1,d0 ;LSB einfügen
ENDM
ReadByteIndX MACRO ;[Ziel] (wird ein Ziel angegeben, ist das CCR gültig)
ReadAdrIndX
ReadByte \1
ENDM
; (Ind),Y
ReadAdrIndY MACRO
move.b (RPC)+,d0
;(Korrekt) move.b (RAMPTR,d0.l),d1 ;LSB lesen
; addq.b #1,d0
; move.b (RAMPTR,d0.l),d0 ;MSB lesen
; lsl.w #8,d0
; move.b d1,d0 ;LSB einfügen
move.w (RAMPTR,d0.l),d0 ;(Abgekürzt)
rol.w #8,d0 ;Geht bei ($ff),y schief
add.w RY,d0
ENDM
ReadByteIndY MACRO ;[Ziel] (wird ein Ziel angegeben, ist das CCR gültig)
ReadAdrIndY
ReadByte \1
ENDM
; Ein Byte auf den Stapel schieben
PushByte MACRO ;Quelle
move.b \1,(RAMPTR,RS.l)
subq.b #1,RS
ENDM
; PC auf Stack schieben
PushPC MACRO
move.w RPC,d0
move.w d0,d1
lsr.w #8,d0
PushByte d0
PushByte d1
ENDM
; PC+1 auf den Stack schieben
PushPCPlus1 MACRO
move.w RPC,d0
addq.w #1,d0
move.w d0,d1
lsr.w #8,d0
PushByte d0
PushByte d1
ENDM
; Status auf Stack schieben
PushP MACRO ;Break-Bit
move.w RP,d0 ;6510-Status holen
lsr.w #8,d0
and.b #$4c,d0 ;V,D,I behalten
IFEQ \1
or.b #$20,d0 ;1-Bit setzen
ELSE
or.b #$30,d0 ;B und 1-Bit setzen
ENDC
tst.b RP ;C dazunehmen
beq \@1$
or.b #$01,d0
\@1$ btst #3,RCCR ;N dazunehmen
beq \@2$
or.b #$80,d0
\@2$ btst #2,RCCR ;Z dazunehmen
beq \@3$
or.b #$02,d0
\@3$ PushByte d0
ENDM
; Ein Byte vom Stapel lesen
PopByte MACRO ;Ziel (CCR ist gültig)
addq.b #1,RS
move.b (RAMPTR,RS.l),\1
ENDM
; Status vom Stack holen
PopP MACRO
PopByte d0
move ccr,RCCR
and.b #$08,RCCR ;N holen
move.b d0,RP
and.b #$4c,RP ;V,D,I behalten
lsl.w #8,RP
btst #1,d0 ;Z holen
beq \@1$
or.b #$04,RCCR
\@1$ btst #0,d0 ;C holen
sne RP
ENDM
; PC setzen
; -> d0.w: 16-Bit-Adresse
; <- RPC.l: Amiga-Adresse
Jump MACRO
move.w d0,d1
lsr.w #8,d1
move.l (256*8*8,RWTAB,d1.l*8),a0 ;JumpTab
jsr (a0)
ENDM
; Nächsten Befehl ausführen
Next MACRO ;Zyklenzahl
IFNE \1
subq.w #\1,(CYCPTR) ;Anzahl Zyklen abziehen
bmi Periodic ;Alle verbraucht: Periodic
ENDC
moveq #0,d0
move.b (RPC)+,d0 ;Opcode lesen
move.l (OpcodeTable,d0.l*4),a0 ;Zeiger auf die Opcode-Routine holen
jmp (a0) ;Routine aufrufen
ENDM
; Speicherkonfiguration anpassen
NewConfig MACRO
;!! move.b (RAMPTR),d0 ;Gelesenes PR richtig berechnen
; move.b d0,d1
; not.b d1
; and.b 1(RAMPTR),d0
; and.b #%00010111,d1 ;Eingabepins
; or.b d1,d0
; move.b d0,1(RAMPTR)
move.b (RAMPTR),d0 ;Zustand der Ausgabepins lesen
not.b d0 ;Eingabepins sind 1
or.b 1(RAMPTR),d0
and.w #7,d0 ;Relevante Bits maskieren
move.l (ConfigTab,d0.l*4),RWTAB
ENDM
; Ein C64-Byte in die Zero-Page schreiben und nächsten Befehl ausführen.
; Prüfen, ob sich die Speicherkonfiguration geändert hat.
; -> d0.w: Adresse (16 bit)
; -> Arg1: Byte
WriteZeroNext MACRO ;Register, Zyklenzahl
move.b \1,(RAMPTR,d0.l)
cmp.b #2,d0
bhs \@1$
NewConfig
\@1$ Next \2
ENDM
*
* Initialisierung
*
; Near-Adressierung initialisieren
CPUTaskProc lea _DATA_BAS_,a4
lea 32766(a4),a4
; Task ermitteln
move.l _SysBase,a6
sub.l a1,a1
JSRLIB FindTask
move.l d0,CPUTask
; Continue-Signal holen
moveq #-1,d0
JSRLIB AllocSignal
move.b d0,ContinueSig
moveq #0,d1
bset d0,d1
move.l d1,ContinueSet
; Grafik initialisieren
jsr _InitDisplayFrom6510
; Signal an den Emulator schicken
move.l _SysBase,a6
move.l MainTask,a1
move.l ReadySet,d0
JSRLIB Signal
; Variablen initilisieren
clr.l Interrupt
clr.b RESETIsEXIT
clr.b RESETIsPause
clr.b NMIState
move.w #63,CyclesLeft
; RAM mit Einschaltmuster initialisieren
move.l TheRAM,a0
move.w #511,d1
3$ moveq #63,d0
1$ clr.b (a0)+ ;Abwechselnd 64 Bytes $00
dbra d0,1$
moveq #63,d0
2$ st (a0)+ ;Und 64 Bytes $ff
dbra d0,2$
dbra d1,3$
; Farb-RAM mit Zufallswerten initialisieren
move.l TheColor,a2
move.w #$03ff,d2
4$ jsr Random
move.b d0,(a2)+
dbra d2,4$
; Speicherkonfiguration initialisieren
move.l TheRAM,RAMPTR
move.b #$00,(RAMPTR) ;Port auf Eingabe
NewConfig
; Register setzen
moveq #0,d0
moveq #0,d1
moveq #0,RA
moveq #0,RX
moveq #0,RY
move.l #$01ff,RS
moveq #0,RCCR
move.l #InterruptMask,RP
lea CyclesLeft,CYCPTR
; Reset-Vektor lesen, PC setzen und ersten Befehl ausführen
move.w #$fffc,d0
ReadWord
Jump
Next 0
; Unbekannten Opcode entdeckt: Requester darstellen
IllegalOp subq.w #1,RPC ;PC korrigieren
movem.l a2-a6,-(sp)
and.w #$00ff,d0 ;Opcode
move.w d0,RequestStream
move.l RPC,d0 ;und PC anzeigen
move.w d0,RequestStream+2
jsr _EmulToBack
move.l _IntuitionBase,a6
sub.l a0,a0
lea IllegalOpReq,a1
move.l a0,a2
lea RequestStream,a3
JSRLIB EasyRequestArgs
move.l d0,-(sp)
jsr _EmulToFront
move.l (sp)+,d0
movem.l (sp)+,a2-a6
tst.l d0 ;Resetten?
beq 1$
jsr ResetC64 ;Ja
moveq #0,d0
moveq #0,d1
bra HandleRESET
1$ move.l a6,-(sp) ;Nein, SAM aufrufen
move.l _SysBase,a6
move.l MainTask,a1 ;Den Haupttask benachrichtigen
move.l InvokeSAMSet,d0
JSRLIB Signal
move.l (sp)+,a6
bsr Pause ;In Pause-Zustand gehen
clr.b IntIsRESET
clr.b RESETIsPause
moveq #0,d0
moveq #0,d1
NewConfig
move.w _RPC,d0
Jump
Next 0
*
* Speicherzugriff Lesen
*
; Lesen aus dem RAM
ReadByteRAM move.b (RAMPTR,d0.l),d0
rts
; Lesen aus dem Basic-ROM
ReadByteBasic and.w #$1fff,d0
move.l TheBasic,a0
move.b (a0,d0.l),d0
rts
; Lesen aus einem VIC-Register
ReadByteVIC and.w #$3f,d0
bra ReadFrom6569
; Lesen aus einem SID-Register
ReadByteSID and.w #$1f,d0
bra ReadFrom6581
; Lesen aus dem Farb-RAM
ReadByteColor and.w #$03ff,d0
move.l TheColor,a0
move.b (a0,d0.l),d1
and.b #$0f,d1
move.l d1,-(sp)
jsr Random ;Oberes Nibble ist Zufallswert
and.b #$f0,d0
move.l (sp)+,d1
or.b d1,d0
rts
; Lesen aus einem CIA 1-Register
ReadByteCIA1 and.w #$0f,d0
bra ReadFrom6526A
; Lesen aus einem CIA 2-Register
ReadByteCIA2 and.w #$0f,d0
bra ReadFrom6526B
; Lesen einer offenen Adresse
ReadByteUndef cmp.l #$dfa0,d0
bhs 1$
jsr Random ;Zufallswert
moveq #0,d1 ;MSW löschen
rts
; $dfa0-$dfff: Emulator-Identifikation
1$ cmp.w #$dfff,d0 ;$dfff liest abwechselnd $55/$aa
bne 2$
move.b DFFFByte,d0
not.b DFFFByte
rts
2$ cmp.w #$dffe,d0 ;$dffe liest "F" (Frodo-Kennung)
bne 3$
moveq #'F',d0
rts
3$ cmp.w #$dffd,d0 ;$dffd: Version
bne 4$
move.b #VERSION,d0
rts
4$ cmp.w #$dffc,d0 ;$dffc: Revision
bne 5$
move.b #REVISION<<4,d0
rts
5$ sub.w #$dfa0,d0 ;$dfa0-$dffb: ID-String
move.b IDString(pc,d0.w),d0
rts
; Lesen aus dem Kernal-ROM
ReadByteKernal and.w #$1fff,d0
move.l TheKernal,a0
move.b (a0,d0.l),d0
rts
; Lesen aus dem Char-ROM
ReadByteChar and.w #$0fff,d0
move.l TheChar,a0
move.b (a0,d0.l),d0
rts
*
* Speicherzugriff Schreiben
* In a1 steht die 16-Bit-Adresse
*
; Schreiben in Seite 0
WriteBytePage0 move.l a1,d0
move.b d1,(RAMPTR,d0.l)
cmp.b #2,d0
bhs 1$
NewConfig
1$ rts
; Schreiben ins RAM
WriteByteRAM move.b d1,(RAMPTR,a1.l)
rts
; Schreiben in ein VIC-Register
WriteByteVIC move.l a1,d0
and.w #$3f,d0
bra WriteTo6569
; Schreiben in ein SID-Register
WriteByteSID move.l a1,d0
and.w #$1f,d0
bra WriteTo6581
; Schreiben ins Farb-RAM
WriteByteColor move.l a1,d0
and.w #$03ff,d0
move.l TheColor,a0
move.b d1,(a0,d0.l)
rts
; Schreiben in ein CIA 1-Register
WriteByteCIA1 move.l a1,d0
and.w #$0f,d0
bra WriteTo6526A
; Schreiben in ein CIA 2-Register
WriteByteCIA2 move.l a1,d0
and.w #$0f,d0
bra WriteTo6526B
; Schreiben an einer offenen Adresse
WriteByteUndef rts
*
* Sprungbefehle
*
; Sprung ins RAM
JumpToRAM lea (RAMPTR,d0.l),RPC
rts
; Sprung ins Basic-ROM
JumpToBasic move.l TheBasic,RPC
and.w #$1fff,d0
add.l d0,RPC
rts
; Sprung ins Kernal-ROM
JumpToKernal move.l TheKernal,RPC
and.w #$1fff,d0
add.l d0,RPC
rts
; Sprung ins Char-ROM (warum sollte jemand sowas tun? Aber egal.)
JumpToChar move.l TheChar,RPC
and.w #$0fff,d0
add.l d0,RPC
rts
; Sprung in den I/O-Bereich (in VIC-Register wird ab und zu gerne gesprungen,
; $de00 und das Farb-RAM sind auch sehr beliebt :-)
JumpToIO movem.l a2-a6,-(sp)
move.w d0,RequestStream ;PC anzeigen
jsr _EmulToBack
move.l _IntuitionBase,a6
sub.l a0,a0
lea JumpToIOReq,a1
move.l a0,a2
lea RequestStream,a3
JSRLIB EasyRequestArgs
jsr _EmulToFront
movem.l (sp)+,a2-a6
jsr ResetC64
moveq #0,d0 ;MSWs von d0 und d1
moveq #0,d1 ; müssen Null sein
addq.l #4,sp ;Rücksprungadresse löschen
bra HandleRESET
**
** Opcode-Routinen
**
*
* Interrupts handhaben
*
; Art des Interrupt feststellen (Priorität)
HandleInt tst.b IntIsRESET
bne HandleRESET
tst.b IntIsNMI
bne HandleNMI
tst.w IntIsIRQ
bne HandleIRQ
; Kein Interrupt, nächsten Befehl ausführen
HandleIntDone Next 0
; IRQ: Interrupt-Bit testen, nach ($fffe) springen
HandleIRQ btst #InterruptBit,RP
beq IRQDoIt
Next 0
IRQDoIt PushPC
PushP 0
or.w #InterruptMask,RP
move.w #$fffe,d0 ;IRQ-Vektor
ReadWord
Jump
Next 7
; NMI: Nach ($fffa) springen
HandleNMI clr.b IntIsNMI ;Simuliert einen flankengetriggerten Eingang
PushPC
PushP 0
or.w #InterruptMask,RP
move.w #$fffa,d0 ;NMI-Vektor
ReadWord
Jump
Next 7
; RESET: Emulator beenden, anhalten oder nach ($fffc) springen
HandleRESET tst.b RESETIsEXIT ;Beenden?
bne HandleEXIT
tst.b RESETIsPause ;Pause?
bne HandlePause
clr.l Interrupt ;Nein, RESET
clr.b NMIState
cmp.l #$c3c2cd38,$8004(RAMPTR)
bne 1$
cmp.b #$30,$8008(RAMPTR)
bne 1$
clr.b $8004(RAMPTR) ;CBM80 löschen, wenn vorhanden
1$ move.b #$00,(RAMPTR) ;Speicherkonfiguration initialisieren (Port auf Eingabe)
NewConfig
move.w #$fffc,d0 ;RESET-Vektor
ReadWord
Jump
Next 0
; EXIT: Signal an den Emulator schicken
HandleEXIT jsr _ExitDisplayFrom6510 ;Grafik aufräumen
move.l _SysBase,a6
moveq #0,d0
move.b ContinueSig,d0
JSRLIB FreeSignal
JSRLIB Forbid
move.l MainTask,a1
move.l ReadySet,d0
JSRLIB Signal
moveq #0,d0
rts
; Pause: Signal an den Emulator schicken und dann selbst auf
; ein Signal warten, Zustand retten und wiederherstellen
HandlePause bsr Pause
moveq #0,d0
moveq #0,d1
NewConfig
move.w _RPC,d0
Jump
Next 0
Pause clr.b IntIsRESET
clr.b RESETIsPause
move.b RA,_RA ;Register für SAM bereitstellen
move.b RX,_RX
move.b RY,_RY
move.w RP,d0
lsr.w #8,d0
and.b #$5c,d0 ;V, B, D, I
or.b #$20,d0 ;1-Bit setzen
tst.b RP ;C dazunehmen
beq 1$
or.b #$01,d0
1$ btst #3,RCCR ;N dazunehmen
beq 2$
or.b #$80,d0
2$ btst #2,RCCR ;Z dazunehmen
beq 3$
or.b #$02,d0
3$ move.b d0,_RP
move.b (RAMPTR),_RDDR
move.b 1(RAMPTR),d0
and.b #$3f,d0
move.b d0,_RPR
move.b (RAMPTR),d0
not.b d0
or.b 1(RAMPTR),d0
and.b #$07,d0
move.b d0,_SAMMemConfig
move.w RPC,_RPC
move.w RS,_RS
move.l _SysBase,a6
move.l MainTask,a1
move.l ReadySet,d0
JSRLIB Signal
move.l ContinueSet,d0
JSRLIB Wait
move.l TheRAM,RAMPTR
lea CyclesLeft,CYCPTR
moveq #0,RA ;Register von SAM lesen
move.b _RA,RA
moveq #0,RX
move.b _RX,RX
moveq #0,RY
move.b _RY,RY
moveq #0,RCCR
btst #7,_RP ;N holen
beq 4$
or.b #$08,RCCR
4$ btst #1,_RP ;Z holen
beq 5$
or.b #$04,RCCR
5$
moveq #0,RP
move.b _RP,RP
and.b #$4c,RP ;V,D,I behalten
lsl.w #8,RP
btst #0,_RP ;C holen
sne RP
move.l #$0100,RS
move.b _RS+1,RS
move.b _RDDR,(RAMPTR)
move.b _RPR,1(RAMPTR)
rts
*
* Opcodes
*
; Laden
LoadA MACRO ;Quelle, Zyklenzahl
move.b \1,RA
move ccr,RCCR
Next \2
ENDM
LoadX MACRO ;Quelle, Zyklenzahl
move.b \1,RX
move ccr,RCCR
Next \2
ENDM
LoadY MACRO ;Quelle, Zyklenzahl
move.b \1,RY
move ccr,RCCR
Next \2
ENDM
LoadAX MACRO ;Quelle, Zyklenzahl
move.b \1,RA
move.b RA,RX
move ccr,RCCR
Next \2
ENDM
LDAImm LoadA (RPC)+,2
LDAZero ReadAdrZero
LoadA (RAMPTR,d0.l),3
LDAZeroX ReadAdrZeroX
LoadA (RAMPTR,d0.l),4
LDAAbs ReadByteAbs RA
move ccr,RCCR
Next 4
LDAAbsX ReadByteAbsX RA
move ccr,RCCR
Next 4
LDAAbsY ReadByteAbsY RA
move ccr,RCCR
Next 4
LDAIndX ReadByteIndX RA
move ccr,RCCR
Next 6
LDAIndY ReadByteIndY RA
move ccr,RCCR
Next 5
LDXImm LoadX (RPC)+,2
LDXZero ReadAdrZero
LoadX (RAMPTR,d0.l),3
LDXZeroY ReadAdrZeroY
LoadX (RAMPTR,d0.l),4
LDXAbs ReadByteAbs RX
move ccr,RCCR
Next 4
LDXAbsY ReadByteAbsY RX
move ccr,RCCR
Next 4
LDYImm LoadY (RPC)+,2
LDYZero ReadAdrZero
LoadY (RAMPTR,d0.l),3
LDYZeroX ReadAdrZeroX
LoadY (RAMPTR,d0.l),4
LDYAbs ReadByteAbs RY
move ccr,RCCR
Next 4
LDYAbsX ReadByteAbsX RY
move ccr,RCCR
Next 4
LAXZero ReadAdrZero
LoadAX (RAMPTR,d0.l),3
LAXZeroY ReadAdrZeroY
LoadAX (RAMPTR,d0.l),4
LAXAbs ReadByteAbs RA
move.b RA,RX
move ccr,RCCR
Next 4
LAXAbsY ReadByteAbsY RA
move.b RA,RX
move ccr,RCCR
Next 4
LAXIndX ReadByteIndX RA
move.b RA,RX
move ccr,RCCR
Next 6
LAXIndY ReadByteIndY RA
move.b RA,RX
move ccr,RCCR
Next 5
; Speichern
StoreA MACRO ;Zyklenzahl
move.b RA,d1
WriteByte
Next \1
ENDM
StoreAX MACRO ;Zyklenzahl
move.b RA,d1
and.b RX,d1
WriteByte
Next \1
ENDM
STAZero ReadAdrZero
WriteZeroNext RA,3
STAZeroX ReadAdrZeroX
WriteZeroNext RA,4
STAAbs ReadAdrAbs
StoreA 4
STAAbsX ReadAdrAbsX
StoreA 5
STAAbsY ReadAdrAbsY
StoreA 5
STAIndX ReadAdrIndX
StoreA 6
STAIndY ReadAdrIndY
StoreA 6
STXZero ReadAdrZero
WriteZeroNext RX,3
STXZeroY ReadAdrZeroY
WriteZeroNext RX,4
STXAbs ReadAdrAbs
move.b RX,d1
WriteByte
Next 4
STYZero ReadAdrZero
WriteZeroNext RY,3
STYZeroX ReadAdrZeroX
WriteZeroNext RY,4
STYAbs ReadAdrAbs
move.b RY,d1
WriteByte
Next 4
SAXZero ReadAdrZero
StoreAX 3
SAXZeroY ReadAdrZeroY
StoreAX 4
SAXAbs ReadAdrAbs
StoreAX 4
SAXIndX ReadAdrIndX
StoreAX 6
; Datentransport zwischen Registern
TAX move.b RA,RX
move ccr,RCCR
Next 2
TAY move.b RA,RY
move ccr,RCCR
Next 2
TXA move.b RX,RA
move ccr,RCCR
Next 2
TYA move.b RY,RA
move ccr,RCCR
Next 2
TXS move.b RX,RS
Next 2
TSX move.b RS,RX
move ccr,RCCR
Next 2
; Stack
PHA PushByte RA
Next 3
PLA PopByte RA
move ccr,RCCR
Next 4
PHP PushP 1 ;Break-Flag setzen
Next 3
PLP PopP
tst.w IntIsIRQ ;Steht ein IRQ an?
beq 1$
btst #InterruptBit,RP ;Ja, I-Flag gelöscht?
beq HandleIRQ ;Ja, Interrupt auslösen
1$ Next 4
; Vergleiche
CompareA MACRO ;Quelle, Zyklenzahl
cmp.b \1,RA
move ccr,RCCR
scc RP ;Inverses Carry holen
Next \2
ENDM
CMPImm CompareA (RPC)+,2
CMPZero ReadAdrZero
CompareA (RAMPTR,d0.l),3
CMPZeroX ReadAdrZeroX
CompareA (RAMPTR,d0.l),4
CMPAbs ReadByteAbs
CompareA d0,4
CMPAbsX ReadByteAbsX
CompareA d0,4
CMPAbsY ReadByteAbsY
CompareA d0,4
CMPIndX ReadByteIndX
CompareA d0,6
CMPIndY ReadByteIndY
CompareA d0,5
CPXImm cmp.b (RPC)+,RX
move ccr,RCCR
scc RP ;Inverses Carry holen
Next 2
CPXZero ReadAdrZero
cmp.b (RAMPTR,d0.l),RX
move ccr,RCCR
scc RP ;Inverses Carry holen
Next 3
CPXAbs ReadByteAbs
cmp.b d0,RX
move ccr,RCCR
scc RP ;Inverses Carry holen
Next 4
CPYImm cmp.b (RPC)+,RY
move ccr,RCCR
scc RP ;Inverses Carry holen
Next 2
CPYZero ReadAdrZero
cmp.b (RAMPTR,d0.l),RY
move ccr,RCCR
scc RP ;Inverses Carry holen
Next 3
CPYAbs ReadByteAbs
cmp.b d0,RY
move ccr,RCCR
scc RP ;Inverses Carry holen
Next 4
; Arithmetische Operationen
AdcA MACRO ;Zyklenzahl
and.w #~OverflowMask,RP
btst #DecimalBit,RP
bne \@2$
add.b RP,RP ;Carry -> X
addx.b d0,RA
scs RP ;Carry holen
bvc \@1$ ;Overflow holen
or.w #OverflowMask,RP
\@1$ tst.b RA ;N und Z holen (wegen addx)
move ccr,RCCR
Next \1
\@2$ bsr AdcDec
Next \1
ENDM
AdcDec move.b d0,TMPS ;Dezimalmodus
move.b RA,TMPA
clr.b RCCR
move.b RA,d1 ;Unteres Nybble berechnen
and.b #$0f,d0
and.b #$0f,d1
add.b RP,RP ;Carry -> X
addx.b d0,d1 ; -> d1
cmp.b #10,d1 ;BCD-Fixup für das untere Nybble
blo 2$
addq.b #6,d1
2$ move.b d1,TMPAL
move.b TMPS,d0 ;Oberes Nybble berechnen
lsr.b #4,d0
lsr.b #4,RA
add.b d0,RA
cmp.b #$10,d1
blo 1$
addq.b #1,RA ; -> d2
1$
move.b TMPS,d0 ;Z holen (wie im Binärmodus)
move.b TMPA,d1
add.b RP,RP ;Carry -> X
addx.b d0,d1
tst.b d1 ;Wegen addx
bne 6$
or.b #$04,RCCR
6$
btst #3,RA ;N berechnen
beq 4$
or.b #$08,RCCR
4$
move.b RA,d0 ;V berechnen
lsl.b #4,d0
move.b TMPA,d1
eor.b d1,d0
bpl 5$
move.b TMPS,d0
eor.b d1,d0
bmi 5$
or.w #OverflowMask,RP
5$
cmp.b #10,RA ;BCD-Fixup für das obere Nybble
blo 3$
addq.b #6,RA
3$
cmp.b #$10,RA ;Carry holen
shs RP
move.b TMPAL,d0 ;Ergebnis zusammensetzen
and.b #$0f,d0
lsl.b #4,RA
or.b d0,RA
rts
ADCImm move.b (RPC)+,d0
AdcA 2
ADCZero ReadByteZero d0
AdcA 3
ADCZeroX ReadByteZeroX d0
AdcA 4
ADCAbs ReadByteAbs
AdcA 4
ADCAbsX ReadByteAbsX
AdcA 4
ADCAbsY ReadByteAbsY
AdcA 4
ADCIndX ReadByteIndX
AdcA 6
ADCIndY ReadByteIndY
AdcA 5
SbcA MACRO ;Zyklenzahl
not.b RP
and.w #~OverflowMask,RP
btst #DecimalBit,RP
bne \@2$
add.b RP,RP ;Inverses Carry -> X
subx.b d0,RA
scc RP ;Inverses Carry holen
bvc \@1$ ;Overflow holen
or.w #OverflowMask,RP
\@1$ tst.b RA
move ccr,RCCR ;N und Z holen (wegen subx)
Next \1
\@2$ bsr SbcDec
Next \1
ENDM
SbcDec move.b d0,TMPS ;Dezimalmodus
move.b RA,TMPA
and.b #$0f,d0 ;Unteres Nybble berechnen
and.b #$0f,RA
add.b RP,RP ;Inverses Carry -> X
subx.b d0,RA
move ccr,d1
bcc 1$ ;BCD-Fixup
subq.b #6,RA
st d1
1$ and.b #$0f,RA
move.b RA,TMPAL
move.b TMPS,d0 ;Oberes Nybble berechnen
move.b TMPA,RA
and.b #$f0,d0
and.b #$f0,RA
sub.b d0,RA
bcc 2$ ;BCD-Fixup
and.b #$f0,RA
sub.b #$60,RA
btst #0,d1
beq 3$
sub.b #$10,RA
bra 3$
2$ and.b #$f0,RA
btst #0,d1
beq 3$
sub.b #$10,RA
bcc 3$
sub.b #$60,RA
3$ or.b TMPAL,RA ;Ergebnis zusammenbauen
add.b RP,RP ;Inverses Carry -> X
move.b TMPS,d0 ;Flags berechnen (wie im Binärmodus)
move.b TMPA,d1
subx.b d0,d1 ;Flags berechnen
scc RP ;Inverses Carry holen
bvc 4$ ;Overflow holen
or.w #OverflowMask,RP
4$ tst.b d1 ;N und Z holen (wegen subx)
move ccr,RCCR
rts
SBCImm move.b (RPC)+,d0
SbcA 2
SBCZero ReadByteZero d0
SbcA 3
SBCZeroX ReadByteZeroX d0
SbcA 4
SBCAbs ReadByteAbs
SbcA 4
SBCAbsX ReadByteAbsX
SbcA 4
SBCAbsY ReadByteAbsY
SbcA 4
SBCIndX ReadByteIndX
SbcA 6
SBCIndY ReadByteIndY
SbcA 5
Increment MACRO ;Zyklenzahl
move.l d0,-(sp)
ReadByte d1
addq.b #1,d1
move ccr,RCCR
move.l (sp)+,d0
WriteByte
Next \1
ENDM
IncrementZero MACRO ;Zyklenzahl
addq.b #1,(RAMPTR,d0.l)
move ccr,RCCR
cmp.b #2,d0
bhs \@1$
NewConfig
\@1$ Next \1
ENDM
INCZero ReadAdrZero
IncrementZero 5
INCZeroX ReadAdrZeroX
IncrementZero 6
INCAbs ReadAdrAbs
Increment 6
INCAbsX ReadAdrAbsX
Increment 7
Decrement MACRO ;Zyklenzahl
move.l d0,-(sp)
ReadByte d1
subq.b #1,d1
move ccr,RCCR
move.l (sp)+,d0
WriteByte
Next \1
ENDM
DecrementZero MACRO ;Zyklenzahl
subq.b #1,(RAMPTR,d0.l)
move ccr,RCCR
cmp.b #2,d0
bhs \@1$
NewConfig
\@1$ Next \1
ENDM
DECZero ReadAdrZero
DecrementZero 5
DECZeroX ReadAdrZeroX
DecrementZero 6
DECAbs ReadAdrAbs
Decrement 6
DECAbsX ReadAdrAbsX
Decrement 7
INX addq.b #1,RX
move ccr,RCCR
Next 2
DEX subq.b #1,RX
move ccr,RCCR
Next 2
INY addq.b #1,RY
move ccr,RCCR
Next 2
DEY subq.b #1,RY
move ccr,RCCR
Next 2
; Logische Operationen
AndA MACRO ;Quelle, Zyklenzahl
and.b \1,RA
move ccr,RCCR
Next \2
ENDM
ANDImm AndA (RPC)+,2
ANDZero ReadAdrZero
AndA (RAMPTR,d0.l),3
ANDZeroX ReadAdrZeroX
AndA (RAMPTR,d0.l),4
ANDAbs ReadByteAbs
AndA d0,4
ANDAbsX ReadByteAbsX
AndA d0,4
ANDAbsY ReadByteAbsY
AndA d0,4
ANDIndX ReadByteIndX
AndA d0,6
ANDIndY ReadByteIndY
AndA d0,5
OrA MACRO ;Quelle, Zyklenzahl
or.b \1,RA
move ccr,RCCR
Next \2
ENDM
ORAImm OrA (RPC)+,2
ORAZero ReadAdrZero
OrA (RAMPTR,d0.l),3
ORAZeroX ReadAdrZeroX
OrA (RAMPTR,d0.l),4
ORAAbs ReadByteAbs
OrA d0,4
ORAAbsX ReadByteAbsX
OrA d0,4
ORAAbsY ReadByteAbsY
OrA d0,4
ORAIndX ReadByteIndX
OrA d0,6
ORAIndY ReadByteIndY
OrA d0,5
EorA MACRO ;Zyklenzahl
eor.b d0,RA ;eor.b (ea),RA geht nicht
move ccr,RCCR ;(Warum nicht, Motorola ?) :-(
Next \1
ENDM
EORImm move.b (RPC)+,d0
EorA 2
EORZero ReadByteZero d0
EorA 3
EORZeroX ReadByteZeroX d0
EorA 4
EORAbs ReadByteAbs
EorA 4
EORAbsX ReadByteAbsX
EorA 4
EORAbsY ReadByteAbsY
EorA 4
EORIndX ReadByteIndX
EorA 6
EORIndY ReadByteIndY
EorA 5
BitTest MACRO ;Zyklenzahl
clr.b RCCR
and.w #~OverflowMask,RP
tst.b d0 ;Bit 7 -> N
bpl \@1$
or.b #$08,RCCR
\@1$
btst #6,d0 ;Bit 6 -> V
beq \@2$
or.w #OverflowMask,RP
\@2$
and.b RA,d0 ;A AND M -> Z
bne \@3$
or.b #$04,RCCR
\@3$ Next \1
ENDM
BITZero ReadByteZero d0
BitTest 3
BITAbs ReadByteAbs
BitTest 4
; Verschiebungen
ShiftLeft MACRO ;Zyklenzahl
move.l d0,-(sp)
ReadByte d1
add.b d1,d1
scs RP ;Carry holen
move ccr,RCCR
move.l (sp)+,d0
WriteByte
Next \1
ENDM
ShiftLeftZero MACRO ;Zyklenzahl
lea (RAMPTR,d0.l),a0
move.b (a0),d1
add.b d1,d1
scs RP ;Carry holen
move.b d1,(a0)
move ccr,RCCR
cmp.b #2,d0
bhs \@1$
NewConfig
\@1$ Next \1
ENDM
ASLA add.b RA,RA
move ccr,RCCR
scs RP ;Carry holen
Next 2
ASLZero ReadAdrZero
ShiftLeftZero 5
ASLZeroX ReadAdrZeroX
ShiftLeftZero 6
ASLAbs ReadAdrAbs
ShiftLeft 6
ASLAbsX ReadAdrAbsX
ShiftLeft 7
ShiftRight MACRO ;Zyklenzahl
move.l d0,-(sp)
ReadByte d1
lsr.b #1,d1
scs RP ;Carry holen
move ccr,RCCR
move.l (sp)+,d0
WriteByte
Next \1
ENDM
ShiftRightZero MACRO ;Zyklenzahl
lea (RAMPTR,d0.l),a0
move.b (a0),d1
lsr.b #1,d1
scs RP ;Carry holen
move.b d1,(a0)
move ccr,RCCR
cmp.b #2,d0
bhs \@1$
NewConfig
\@1$ Next \1
ENDM
LSRA lsr.b #1,RA
move ccr,RCCR
scs RP ;Carry holen
Next 2
LSRZero ReadAdrZero
ShiftRightZero 5
LSRZeroX ReadAdrZeroX
ShiftRightZero 6
LSRAbs ReadAdrAbs
ShiftRight 6
LSRAbsX ReadAdrAbsX
ShiftRight 7
RotateLeft MACRO ;Zyklenzahl
move.l d0,-(sp)
ReadByte d1
add.b RP,RP ;Carry -> X
roxl.b #1,d1
scs RP ;Carry holen
move ccr,RCCR
move.l (sp)+,d0
WriteByte
Next \1
ENDM
RotateLeftZero MACRO ;Zyklenzahl
lea (RAMPTR,d0.l),a0
move.b (a0),d1
add.b RP,RP ;Carry -> X
roxl.b #1,d1
scs RP ;Carry holen
move.b d1,(a0)
move ccr,RCCR
cmp.b #2,d0
bhs \@1$
NewConfig
\@1$ Next \1
ENDM
ROLA add.b RP,RP ;Carry -> X
roxl.b #1,RA
move ccr,RCCR
scs RP ;Carry holen
Next 2
ROLZero ReadAdrZero
RotateLeftZero 5
ROLZeroX ReadAdrZeroX
RotateLeftZero 6
ROLAbs ReadAdrAbs
RotateLeft 6
ROLAbsX ReadAdrAbsX
RotateLeft 7
RotateRight MACRO ;Zyklenzahl
move.l d0,-(sp)
ReadByte d1
add.b RP,RP ;Carry -> X
roxr.b #1,d1
scs RP ;Carry holen
move ccr,RCCR
move.l (sp)+,d0
WriteByte
Next \1
ENDM
RotateRightZero MACRO ;Zyklenzahl
lea (RAMPTR,d0.l),a0
move.b (a0),d1
add.b RP,RP ;Carry -> X
roxr.b #1,d1
scs RP ;Carry holen
move.b d1,(a0)
move ccr,RCCR
cmp.b #2,d0
bhs \@1$
NewConfig
\@1$ Next \1
ENDM
RORA add.b RP,RP ;Carry -> X
roxr.b #1,RA
move ccr,RCCR
scs RP ;Carry holen
Next 2
RORZero ReadAdrZero
RotateRightZero 5
RORZeroX ReadAdrZeroX
RotateRightZero 6
RORAbs ReadAdrAbs
RotateRight 6
RORAbsX ReadAdrAbsX
RotateRight 7
; Sprünge/Verzweigungen
JMPAbs ReadAdrAbs
Jump
Next 3
JMPInd ReadAdrInd
Jump
Next 5
JSRAbs PushPCPlus1
ReadAdrAbs
Jump
Next 6
RTSImpl PopByte d1 ;LSB
PopByte d0 ;MSB
lsl.w #8,d0 ;schieben
move.b d1,d0 ;LSB dazunehmen
addq.w #1,d0 ;Adresse um eins erhöhen
Jump
Next 6
RTIImpl PopP
PopByte d1 ;LSB
PopByte d0 ;MSB
lsl.w #8,d0 ;schieben
move.b d1,d0 ;LSB dazunehmen
Jump
tst.w IntIsIRQ ;Steht ein IRQ an?
beq 1$
btst #InterruptBit,RP ;Ja, I-Flag gelöscht?
beq HandleIRQ ;Ja, Interrupt auslösen
1$ Next 6
BRK PushPC
PushP 1
or.w #InterruptMask,RP
move.w #$fffe,d0 ;IRQ-Vektor
ReadWord
Jump
Next 7
Branch MACRO
ReadByteRel
move.l RPC,d1
add.w d0,d1
move.l d1,RPC
moveq #0,d1
Next 3
ENDM
BVCRel btst #OverflowBit,RP
bne BVCNot
Branch
BVCNot addq.l #1,RPC
Next 2
BVSRel btst #OverflowBit,RP
beq BVSNot
Branch
BVSNot addq.l #1,RPC
Next 2
BEQRel btst #2,RCCR
beq BEQNot
Branch
BEQNot addq.l #1,RPC
Next 2
BNERel btst #2,RCCR
bne BNENot
Branch
BNENot addq.l #1,RPC
Next 2
BPLRel btst #3,RCCR
bne BPLNot
Branch
BPLNot addq.l #1,RPC
Next 2
BMIRel btst #3,RCCR
beq BMINot
Branch
BMINot addq.l #1,RPC
Next 2
BCCRel tst.b RP
bne BCCNot
Branch
BCCNot addq.l #1,RPC
Next 2
BCSRel tst.b RP
beq BCSNot
Branch
BCSNot addq.l #1,RPC
Next 2
; Statusregister
SEI or.w #InterruptMask,RP
Next 2
CLI and.w #~InterruptMask,RP
tst.w IntIsIRQ ;Steht ein IRQ an?
bne HandleIRQ ;Ja, auslösen
Next 2
CLC clr.b RP
Next 2
SEC st.b RP
Next 2
SED or.w #DecimalMask,RP
Next 2
CLD and.w #~DecimalMask,RP
Next 2
CLV and.w #~OverflowMask,RP
Next 2
*
* Periodic: Wird über den Opcode-Fetch aufgerufen,
* wenn der Zyklenzähler unterläuft
* Sitzt hier in der Mitte, um kurze Branches ausnutzen zu können
*
; VIC und CIA aufrufen
Periodic lea RegStore+20,a0
movem.w d2-d7,-(a0) ;Gerade Anzahl von Registern
movem.l RWTAB/RPC,-(a0)
bra Periodic6569 ;Springt nach Periodic6526 und hierher zurück
Peri6526Cont lea _DATA_BAS_,a4
lea 32766(a4),a4
movem.l RegStore,RWTAB/RPC
movem.w RegStore+8,d2-d7
move.l TheRAM,RAMPTR
lea CyclesLeft,CYCPTR
moveq #0,d0
moveq #0,d1
; Interrupt aufgetreten?
tst.l Interrupt
bne HandleInt
; Nein, Nächsten Befehl ausführen
Next 0
; Leerbefehle
NOPImpl Next 2
NOPZero addq.w #1,RPC
Next 3
NOPZeroX addq.w #1,RPC
Next 4
NOPAbsX
NOPAbs addq.w #2,RPC
Next 4
; ASL/ORA-Gruppe
ShLeftOr MACRO ;Zyklenzahl
move.l d0,-(sp)
ReadByte d1
add.b d1,d1
scs RP ;Carry holen
or.b d1,RA
move ccr,RCCR
move.l (sp)+,d0
WriteByte
Next \1
ENDM
ShLeftOrZero MACRO ;Zyklenzahl
lea (RAMPTR,d0.l),a0
move.b (a0),d1
add.b d1,d1
scs RP ;Carry holen
or.b d1,RA
move ccr,RCCR
move.b d1,(a0)
cmp.b #2,d0
bhs \@1$
NewConfig
\@1$ Next \1
ENDM
SLOZero ReadAdrZero
ShLeftOrZero 5
SLOZeroX ReadAdrZeroX
ShLeftOrZero 6
SLOAbs ReadAdrAbs
ShLeftOr 6
SLOAbsX ReadAdrAbsX
ShLeftOr 7
SLOAbsY ReadAdrAbsY
ShLeftOr 7
SLOIndX ReadAdrIndX
ShLeftOr 8
SLOIndY ReadAdrIndY
ShLeftOr 8
; ROL/AND-Gruppe
RoLeftAnd MACRO ;Zyklenzahl
move.l d0,-(sp)
ReadByte d1
add.b RP,RP ;Carry -> X
roxl.b #1,d1
scs RP ;Carry holen
and.b d1,RA
move ccr,RCCR ;N und Z holen
move.l (sp)+,d0
WriteByte
Next \1
ENDM
RoLeftAndZero MACRO ;Zyklenzahl
lea (RAMPTR,d0.l),a0
move.b (a0),d1
add.b RP,RP ;Carry -> X
roxl.b #1,d1
scs RP ;Carry holen
and.b d1,RA
move ccr,RCCR ;N und Z holen
move.b d1,(a0)
cmp.b #2,d0
bhs \@1$
NewConfig
\@1$ Next \1
ENDM
RLAZero ReadAdrZero
RoLeftAndZero 5
RLAZeroX ReadAdrZeroX
RoLeftAndZero 6
RLAAbs ReadAdrAbs
RoLeftAnd 6
RLAAbsX ReadAdrAbsX
RoLeftAnd 7
RLAAbsY ReadAdrAbsY
RoLeftAnd 7
RLAIndX ReadAdrIndX
RoLeftAnd 8
RLAIndY ReadAdrIndY
RoLeftAnd 8
; LSR/EOR-Gruppe
ShRightEor MACRO ;Zyklenzahl
move.l d0,-(sp)
ReadByte d1
lsr.b #1,d1
scs RP ;Carry holen
eor.b d1,RA
move ccr,RCCR
move.l (sp)+,d0
WriteByte
Next \1
ENDM
ShRightEorZero MACRO ;Zyklenzahl
lea (RAMPTR,d0.l),a0
move.b (a0),d1
lsr.b #1,d1
scs RP ;Carry holen
eor.b d1,RA
move ccr,RCCR
move.b d1,(a0)
cmp.b #2,d0
bhs \@1$
NewConfig
\@1$ Next \1
ENDM
SREZero ReadAdrZero
ShRightEorZero 5
SREZeroX ReadAdrZeroX
ShRightEorZero 6
SREAbs ReadAdrAbs
ShRightEor 6
SREAbsX ReadAdrAbsX
ShRightEor 7
SREAbsY ReadAdrAbsY
ShRightEor 7
SREIndX ReadAdrIndX
ShRightEor 8
SREIndY ReadAdrIndY
ShRightEor 8
; ROR/ADC-Gruppe
RoRightAdc MACRO ;Zyklenzahl
move.l d0,-(sp)
ReadByte d1
add.b RP,RP ;Carry -> X
roxr.b #1,d1
scs RP ;Carry holen
addx.b d1,RA
bvc \@2$ ;Overflow holen
or.w #OverflowMask,RP
bra \@3$
\@2$ and.w #~OverflowMask,RP
\@3$ tst.b RA
move ccr,RCCR ;N und Z holen
move.l (sp)+,d0
WriteByte
Next \1
ENDM
RoRightAdcZero MACRO ;Zyklenzahl
lea (RAMPTR,d0.l),a0
move.b (a0),d1
add.b RP,RP ;Carry -> X
roxr.b #1,d1
addx.b d1,RA
scs RP ;Carry holen
bvc \@2$ ;Overflow holen
or.w #OverflowMask,RP
bra \@3$
\@2$ and.w #~OverflowMask,RP
\@3$ tst.b RA
move ccr,RCCR ;N und Z holen
move.b d1,(a0)
cmp.b #2,d0
bhs \@1$
NewConfig
\@1$ Next \1
ENDM
RRAZero ReadAdrZero
RoRightAdcZero 5
RRAZeroX ReadAdrZeroX
RoRightAdcZero 6
RRAAbs ReadAdrAbs
RoRightAdc 6
RRAAbsX ReadAdrAbsX
RoRightAdc 7
RRAAbsY ReadAdrAbsY
RoRightAdc 7
RRAIndX ReadAdrIndX
RoRightAdc 8
RRAIndY ReadAdrIndY
RoRightAdc 8
; DEC/CMP-Gruppe
DecCompare MACRO ;Zyklenzahl
move.l d0,-(sp)
ReadByte d1
subq.b #1,d1
cmp.b d1,RA
move ccr,RCCR
scc RP ;Inverses Carry holen
move.l (sp)+,d0
WriteByte
Next \1
ENDM
DecCompareZero MACRO ;Zyklenzahl
lea (RAMPTR,d0.l),a0
move.b (a0),d1
subq.b #1,d1
cmp.b d1,RA
move ccr,RCCR
scc RP ;Inverses Carry holen
move.b d1,(a0)
cmp.b #2,d0
bhs \@1$
NewConfig
\@1$ Next \1
ENDM
DCPZero ReadAdrZero
DecCompareZero 5
DCPZeroX ReadAdrZeroX
DecCompareZero 6
DCPAbs ReadAdrAbs
DecCompare 6
DCPAbsX ReadAdrAbsX
DecCompare 7
DCPAbsY ReadAdrAbsY
DecCompare 7
DCPIndX ReadAdrIndX
DecCompare 8
DCPIndY ReadAdrIndY
DecCompare 8
; INC/SBC-Gruppe
IncSbc MACRO ;Zyklenzahl
move.l d0,-(sp)
ReadByte d1
addq.b #1,d1
not.b RP
add.b RP,RP ;Inverses Carry -> X
subx.b d1,RA
scc RP ;Inverses Carry holen
bvc \@2$ ;Overflow holen
or.w #OverflowMask,RP
bra \@3$
\@2$ and.w #~OverflowMask,RP
\@3$ tst.b RA ;N und Z holen
move ccr,RCCR
move.l (sp)+,d0
WriteByte
Next \1
ENDM
IncSbcZero MACRO ;Zyklenzahl
lea (RAMPTR,d0.l),a0
move.b (a0),d1
addq.b #1,d1
not.b RP
add.b RP,RP ;Inverses Carry -> X
subx.b d1,RA
scc RP ;Inverses Carry holen
bvc \@2$ ;Overflow holen
or.w #OverflowMask,RP
bra \@3$
\@2$ and.w #~OverflowMask,RP
\@3$ tst.b RA ;N und Z holen
move ccr,RCCR
move.b d1,(a0)
cmp.b #2,d0
bhs \@1$
NewConfig
\@1$ Next \1
ENDM
ISBZero ReadAdrZero
IncSbcZero 5
ISBZeroX ReadAdrZeroX
IncSbcZero 6
ISBAbs ReadAdrAbs
IncSbc 6
ISBAbsX ReadAdrAbsX
IncSbc 7
ISBAbsY ReadAdrAbsY
IncSbc 7
ISBIndX ReadAdrIndX
IncSbc 8
ISBIndY ReadAdrIndY
IncSbc 8
; Komplexe (undokumentierte) Funktionen
ANCImm and.b (RPC)+,RA ;??? ($0b, $2b)
move ccr,RCCR
smi.b RP ;N -> C (??)
Next 2
ASRImm and.b (RPC)+,RA
lsr.b #1,RA
move ccr,RCCR
scs RP ;Carry holen
Next 2
ARRImm and.b (RPC)+,RA
add.b RP,RP ;Carry -> X
roxr.b #1,RA
move ccr,RCCR
scs RP ;Carry holen
Next 2
ANEImm or.b #$ee,RA
and.b (RPC)+,RA
and.b RX,RA
move ccr,RCCR
Next 2
LXAImm and.b (RPC)+,RA
move.b RA,RX
move ccr,RCCR
Next 2
LASAbsY ReadByteAbsY ;??? ($bb)
and.b RS,d0
move.b d0,RX
move.b d0,RA
move ccr,RCCR
Next 4
SHAAbsY ReadPCWord
move.w d0,d1
lsr.w #8,d1
addq.b #1,d1
and.b RX,d1
and.b RA,d1
add.w RY,d0
WriteByte
Next 5
SHAIndY moveq #0,d0
move.b (RPC)+,d0
move.w (RAMPTR,d0.l),d0 ;(Abgekürzt)
rol.w #8,d0 ;Geht bei ($ff),y schief
move.w d0,d1
lsr.w #8,d1
addq.b #1,d1
and.b RX,d1
and.b RA,d1
add.w RY,d0
WriteByte
Next 6
SHXAbsY ReadPCWord
move.w d0,d1
lsr.w #8,d1
addq.b #1,d1
and.b RY,d1
add.w RY,d0
WriteByte
Next 5
SHYAbsX ReadPCWord
move.w d0,d1
lsr.w #8,d1
addq.b #1,d1
and.b RX,d1
add.w RX,d0
WriteByte
Next 5
SHSAbsY move.b RA,RS
and.b RX,RS
ReadPCWord
move.w d0,d1
lsr.w #8,d1
addq.b #1,d1
and.b RS,d1
WriteByte
Next 5
SBXImm and.b RA,RX
sub.b (RPC)+,RX
move ccr,RCCR
scc RP ;Inverses Carry holen
Next 2
*
* Erweiterte Opcodes
*
; $d2
OpWrap move.l RPC,d1 ;Wraparound nach $100xx?
sub.l RAMPTR,d1
swap d1
cmp.w #1,d1
bne IllegalOp
sub.l #$10001,RPC ;Ja, zu $00xx umleiten
moveq #0,d1
Next 0
; $f2 $xx
OpIEC move.b (RPC)+,d0 ;Selektor holen
beq OpIECOut
cmp.b #1,d0
beq OpIECOutATN
cmp.b #2,d0
beq OpIECOutSec
cmp.b #3,d0
beq OpIECIn
cmp.b #4,d0
beq OpIECSetATN
cmp.b #5,d0
beq OpIECRelATN
cmp.b #6,d0
beq OpIECTurnaround
cmp.b #7,d0
beq OpIECRelease
bra IllegalOp
OpIECOut move.b $95(RAMPTR),d0 ;Auszugebendes Byte holen
move.b $a3(RAMPTR),d1 ;EOI-Flag holen
bsr IECOut
bra IECSetST
OpIECOutATN move.b $95(RAMPTR),d0 ;Auszugebendes Byte holen
bsr IECOutATN
bra IECSetST
OpIECOutSec move.b $95(RAMPTR),d0 ;Auszugebendes Byte holen
bsr IECOutSec
bra IECSetST
OpIECIn bsr IECIn
move.b d1,RA ;Byte in den Akku
move ccr,RCCR ;Flags entsprechend setzen
bra IECSetST
OpIECSetATN bsr IECSetATN
moveq #0,d0 ;MSWs von d0 und d1 löschen
moveq #0,d1
move.w #$edfb,d0 ;Nach $edfb springen
Jump
Next 0
OpIECRelATN bsr IECRelATN
bra IECReturn
OpIECTurnaround bsr IECTurnaround
bra IECReturn
OpIECRelease bsr IECRelease
bra IECReturn
IECSetST or.b d0,$90(RAMPTR) ;Status setzen
clr.b RP ;Carry löschen
IECReturn moveq #0,d0 ;MSWs von d0 und d1 löschen
moveq #0,d1
bra RTSImpl ;RTS ausführen
**
** Konstanten
**
*
* Opcode Dispatch Table
* "*" bezeichnet einen undokumentierten Opcode
*
CNOP 0,4
OpcodeTable dc.l BRK ;$00
dc.l ORAIndX
dc.l IllegalOp
dc.l SLOIndX ;*
dc.l NOPZero ;*
dc.l ORAZero
dc.l ASLZero
dc.l SLOZero ;*
dc.l PHP ;$08
dc.l ORAImm
dc.l ASLA
dc.l ANCImm ;*
dc.l NOPAbs ;*
dc.l ORAAbs
dc.l ASLAbs
dc.l SLOAbs ;*
dc.l BPLRel ;$10
dc.l ORAIndY
dc.l IllegalOp
dc.l SLOIndY ;*
dc.l NOPZeroX ;*
dc.l ORAZeroX
dc.l ASLZeroX
dc.l SLOZeroX ;*
dc.l CLC ;$18
dc.l ORAAbsY
dc.l NOPImpl ;*
dc.l SLOAbsY ;*
dc.l NOPAbsX ;*
dc.l ORAAbsX
dc.l ASLAbsX
dc.l SLOAbsX
dc.l JSRAbs ;$20
dc.l ANDIndX
dc.l IllegalOp
dc.l RLAIndX ;*
dc.l BITZero
dc.l ANDZero
dc.l ROLZero
dc.l RLAZero ;*
dc.l PLP ;$28
dc.l ANDImm
dc.l ROLA
dc.l ANCImm ;*
dc.l BITAbs
dc.l ANDAbs
dc.l ROLAbs
dc.l RLAAbs ;*
dc.l BMIRel ;$30
dc.l ANDIndY
dc.l IllegalOp
dc.l RLAIndY ;*
dc.l NOPZeroX ;*
dc.l ANDZeroX
dc.l ROLZeroX
dc.l RLAZeroX ;*
dc.l SEC ;$38
dc.l ANDAbsY
dc.l NOPImpl ;*
dc.l RLAAbsY ;*
dc.l NOPAbsX ;*
dc.l ANDAbsX
dc.l ROLAbsX
dc.l RLAAbsX ;*
dc.l RTIImpl ;$40
dc.l EORIndX
dc.l IllegalOp
dc.l SREIndX ;*
dc.l NOPZero ;*
dc.l EORZero
dc.l LSRZero
dc.l SREZero ;*
dc.l PHA ;$48
dc.l EORImm
dc.l LSRA
dc.l ASRImm ;*
dc.l JMPAbs
dc.l EORAbs
dc.l LSRAbs
dc.l SREAbs ;*
dc.l BVCRel ;$50
dc.l EORIndY
dc.l IllegalOp
dc.l SREIndY ;*
dc.l NOPZeroX ;*
dc.l EORZeroX
dc.l LSRZeroX
dc.l SREZeroX ;*
dc.l CLI ;$58
dc.l EORAbsY
dc.l NOPImpl ;*
dc.l SREAbsY ;*
dc.l NOPAbsX ;*
dc.l EORAbsX
dc.l LSRAbsX
dc.l SREAbsX ;*
dc.l RTSImpl ;$60
dc.l ADCIndX
dc.l IllegalOp
dc.l RRAIndX ;*
dc.l NOPZero ;*
dc.l ADCZero
dc.l RORZero
dc.l RRAZero ;*
dc.l PLA ;$68
dc.l ADCImm
dc.l RORA
dc.l ARRImm ;*
dc.l JMPInd
dc.l ADCAbs
dc.l RORAbs
dc.l RRAAbs ;*
dc.l BVSRel ;$70
dc.l ADCIndY
dc.l IllegalOp
dc.l RRAIndY ;*
dc.l NOPZeroX ;*
dc.l ADCZeroX
dc.l RORZeroX
dc.l RRAZeroX ;*
dc.l SEI ;$78
dc.l ADCAbsY
dc.l NOPImpl ;*
dc.l RRAAbsY ;*
dc.l NOPAbsX ;*
dc.l ADCAbsX
dc.l RORAbsX
dc.l RRAAbsX ;*
dc.l NOPZero ;* $80
dc.l STAIndX
dc.l NOPZero ;*
dc.l SAXIndX ;*
dc.l STYZero
dc.l STAZero
dc.l STXZero
dc.l SAXZero ;*
dc.l DEY ;$88
dc.l NOPZero ;*
dc.l TXA
dc.l ANEImm ;*
dc.l STYAbs
dc.l STAAbs
dc.l STXAbs
dc.l SAXAbs ;*
dc.l BCCRel ;$90
dc.l STAIndY
dc.l IllegalOp
dc.l SHAIndY ;*
dc.l STYZeroX
dc.l STAZeroX
dc.l STXZeroY
dc.l SAXZeroY ;*
dc.l TYA ;$98
dc.l STAAbsY
dc.l TXS
dc.l SHSAbsY ;*
dc.l SHYAbsX ;*
dc.l STAAbsX
dc.l SHXAbsY ;*
dc.l SHAAbsY ;*
dc.l LDYImm ;$a0
dc.l LDAIndX
dc.l LDXImm
dc.l LAXIndX ;*
dc.l LDYZero
dc.l LDAZero
dc.l LDXZero
dc.l LAXZero ;*
dc.l TAY ;$a8
dc.l LDAImm
dc.l TAX
dc.l LXAImm ;*
dc.l LDYAbs
dc.l LDAAbs
dc.l LDXAbs
dc.l LAXAbs ;*
dc.l BCSRel ;$b0
dc.l LDAIndY
dc.l IllegalOp
dc.l LAXIndY ;*
dc.l LDYZeroX
dc.l LDAZeroX
dc.l LDXZeroY
dc.l LAXZeroY ;*
dc.l CLV ;$b8
dc.l LDAAbsY
dc.l TSX
dc.l LASAbsY ;*
dc.l LDYAbsX
dc.l LDAAbsX
dc.l LDXAbsY
dc.l LAXAbsY ;*
dc.l CPYImm ;$c0
dc.l CMPIndX
dc.l NOPZero ;*
dc.l DCPIndX ;*
dc.l CPYZero
dc.l CMPZero
dc.l DECZero
dc.l DCPZero ;*
dc.l INY ;$c8
dc.l CMPImm
dc.l DEX
dc.l SBXImm ;*
dc.l CPYAbs
dc.l CMPAbs
dc.l DECAbs
dc.l DCPAbs ;*
dc.l BNERel ;$d0
dc.l CMPIndY
dc.l OpWrap
dc.l DCPIndY ;*
dc.l NOPZeroX ;*
dc.l CMPZeroX
dc.l DECZeroX
dc.l DCPZeroX ;*
dc.l CLD ;$d8
dc.l CMPAbsY
dc.l NOPImpl ;*
dc.l DCPAbsY ;*
dc.l NOPAbsX ;*
dc.l CMPAbsX
dc.l DECAbsX
dc.l DCPAbsX ;*
dc.l CPXImm ;$e0
dc.l SBCIndX
dc.l NOPZero ;*
dc.l ISBIndX ;*
dc.l CPXZero
dc.l SBCZero
dc.l INCZero
dc.l ISBZero ;*
dc.l INX ;$e8
dc.l SBCImm
dc.l NOPImpl
dc.l SBCImm ;*
dc.l CPXAbs
dc.l SBCAbs
dc.l INCAbs
dc.l ISBAbs ;*
dc.l BEQRel ;$f0
dc.l SBCIndY
dc.l OpIEC ;Patch
dc.l ISBIndY ;*
dc.l NOPZeroX ;*
dc.l SBCZeroX
dc.l INCZeroX
dc.l ISBZeroX ;*
dc.l SED ;$f8
dc.l SBCAbsY
dc.l NOPImpl ;*
dc.l ISBAbsY ;*
dc.l NOPAbsX ;*
dc.l SBCAbsX
dc.l INCAbsX
dc.l ISBAbsX ;*
*
* Speicherkonfigurationstabelle
*
; Diese Tabelle enthält für alle 8 Speicherkonfigurationen
; die Zeiger auf die zugehörigen Read- und WriteTabs
CNOP 0,4
ConfigTab dc.l ReadWriteTab0
dc.l ReadWriteTab1
dc.l ReadWriteTab2
dc.l ReadWriteTab3
dc.l ReadWriteTab4
dc.l ReadWriteTab5
dc.l ReadWriteTab6
dc.l ReadWriteTab7
*
* Sonstige Konstanten
*
; Taglist für CreateNewProc
ProcTags dc.l NP_Entry,CPUTaskProc
dc.l NP_Name,CPUTaskName
dc.l NP_Priority,-1
dc.l 0
; Strings
CPUTaskName dc.b "6510",0
IDString dc.b "FRODO V2.0",13
dc.b "(C)1994-1995 CHRISTIAN BAUER",0
ds.b 64 ;Muß mind. 92 Zeichen lang sein
; Flag: Dies ist nicht Frodo SC
CNOP 0,4
_IsFrodoSC
IsFrodoSC dc.w 0
**
** Initialisierte Daten
**
SECTION "DATA",DATA
; Requester
IllegalOpReq dc.l 20,0,0,0,0
JumpToIOReq dc.l 20,0,0,0,0
; Emulator-Kennung
DFFFByte dc.b $55 ;Wechselt bei jedem Lesen zwischen $55 und $aa
**
** Nicht initialisierte Daten
**
SECTION "BSS",BSS
; Sprungtabellen für Speicherzugriff: Zwei Einträge pro Seite (Lesen/Schreiben)
; Eine Tabelle für jede der 8 Speicherkonfigurationen
ReadWriteTab0 ds.l 512
ReadWriteTab1 ds.l 512
ReadWriteTab2 ds.l 512
ReadWriteTab3 ds.l 512
ReadWriteTab4 ds.l 512
ReadWriteTab5 ds.l 512
ReadWriteTab6 ds.l 512
ReadWriteTab7 ds.l 512
; Sprungtabellen für Sprungbefehle: Einen Eintrag pro Seite (8 Bytes, nur
; die ersten 4 Bytes benutzt)
JumpTab0 ds.l 512
JumpTab1 ds.l 512
JumpTab2 ds.l 512
JumpTab3 ds.l 512
JumpTab4 ds.l 512
JumpTab5 ds.l 512
JumpTab6 ds.l 512
JumpTab7 ds.l 512
SECTION "__MERGED",BSS
; 6510-Task
CNOP 0,4
CPUProc ds.l 1 ;Prozess-Handle
XDEF _CPUTask
_CPUTask
CPUTask ds.l 1 ;Task des Prozesses
ReadySet ds.l 1 ;Signal des Hauptprogramms
_InvokeSAMSet
InvokeSAMSet ds.l 1 ;Signal -> Hauptprogramm: SAM aufrufen
ContinueSet ds.l 1 ;Signal des CPU-Tasks
ReadySig ds.b 1
InvokeSAMSig ds.b 1
ContinueSig ds.b 1
; Interrupt-Flags. Bei einem Interrupt wird eins dieser Flags gesetzt.
; Das bewirkt, daß nach dem nächsten Periodic der 6510-Task in die
; Routine "HandleInt" springt. Dort werden diese Flags ausgewertet und
; entsprechend verzweigt.
CNOP 0,4
Interrupt ;Zusammenfassung als Langwort
IntIsRESET ds.b 1 ;RESET aufgetreten, 6510 beenden oder Pause
IntIsNMI ds.b 1 ;NMI aufgetreten
IntIsIRQ ;Zusammenfassung als Wort
IntIsVICIRQ ds.b 1 ;IRQ durch VIC aufgetreten
IntIsCIAIRQ ds.b 1 ;IRQ durch CIA-A aufgetreten
RESETIsEXIT ds.b 1 ;Zur Unterscheidung von RESET und EXIT
RESETIsPause ds.b 1 ;Zur Unterscheidung von RESET und Pause
NMIState ds.b 1 ;Aktueller Zustand der NMI-Leitung (für Flankentriggerung)
; Zwischenspeicher für Adc/Sbc im Dezimalmodus
TMPS ds.b 1
TMPA ds.b 1
TMPAL ds.b 1
; Anzahl zur Verfügung stehender CPU-Zyklen bis zum nächsten Periodic
CNOP 0,2
CyclesLeft ds.w 1
; Speicherzeiger (außer bei TheChar stimmt bei allen das untere Wort
; mit der tatsächlichen C64-Adresse überein, also
; TheRAM : xxxx0000
; TheBasic : xxxxa000
; TheKernal: xxxxe000
; TheColor : xxxxd800
CNOP 0,4
TheRAM ds.l 1 ;Zeiger auf C64-RAM (64K)
TheBasic ds.l 1 ;Zeiger auf Basic-ROM
TheKernal ds.l 1 ;Zeiger auf Kernal-ROM
TheChar ds.l 1 ;Zeiger auf Char-ROM
TheColor ds.l 1 ;Zeiger auf Farb-RAM
; Zwischenspeicher für Register bei Periodic/ReadWord/ReadAdrInd
RegStore ds.l 5
; Argumente für Requester
RequestStream ds.l 16
; Registerinhalte für SAM, nur gültig innerhalb von Pause6510/Resume6510
XDEF _RA
_RA ds.b 1
XDEF _RX
_RX ds.b 1
XDEF _RY
_RY ds.b 1
XDEF _RP
_RP ds.b 1
XDEF _RPR
_RPR ds.b 1
XDEF _RDDR
_RDDR ds.b 1
XDEF _RPC
_RPC ds.w 1
XDEF _RS
_RS ds.w 1
XDEF _SAMMemConfig
_SAMMemConfig ds.b 1 ;CHAREN, LORAM, HIRAM
END